/**
 * 将 Animation 模块拆分为 SlideAnimation 与 ShapeAnimationEnum
 *  SlideAnimation 专注于处理幻灯片切换动画
 *  ShapeAnimationEnum 专注于处理图形动画
 *
 *   1. 元素动画则通过 gsap 库实现，应用在 Konva.Node 上
 *    1.1 这里的动画其实是一个时间线，从某个节点状态运行到另一个节点状态
 *    1.2 官网： https://gsap.com/docs/v3/
 *    1.3 官网上提供了很多动画，这里只使用 gsap 的 timeline 来实现动画
 *    1.4 同样需要记录 动画状态，在预览时，通过动画状态来应用动画；
 *
 * konva Graph 动画
 *  - css animation 参考： https://animate.style/
 *  - Tween 方案： https://konvajs.org/api/Konva.Tween.html
 *  - Animation 方案： https://konvajs.org/api/Konva.Animation.html
 *  - Gsap 方案：https://greensock.com/docs/v3/GSAP
 *
 *  实现思路：
 *    1. 一个元素可能有多个动画：强调动画、入场动画、出场动画，使用 animationList 记录单个节点的动画列表
 *    2. 还需要考虑非预览状态下，应用动画后的状态是否与初始状态一致，使用 resetShapeState 恢复初始状态
 *    3. 使用 gsap 实现，因为 Animation 的属性很多都是不可控的(Animation 方案是通过requestAnimationFrame，时间上不准确)
 *    4. 需要记录原始状态（opacity、width、height、scale 等），非预览状态下还原状态
 */

import Konva from "konva";
import { Draw } from "./Draw";
import { IKeyMap } from "../Interface/Pptx";
import { IShapeAnimation } from "../Interface/Animation";
import { ShapeAnimationEnum } from "../Enumerate/ShapeAnimation";
import {
  ANIMATION_BACKINDOWN,
  ANIMATION_BACKOUTDOWN,
  ANIMATION_FADEIN,
  ANIMATION_FADEOUT,
  ANIMATION_FLASH,
  ANIMATION_HEARTBEAT,
  ANIMATION_ROTATEIN,
  ANIMATION_ROTATEOUT,
  ANIMATION_SHAKEX,
  ANIMATION_ZOOMIN,
  ANIMATION_ZOOMOUT,
} from "../Config/shape-animation-handle";

export class ShapeAnimation {
  private draw: Draw;

  constructor(draw: Draw) {
    this.draw = draw;
  }

  // 设置动画
  public setAnimation(payload: IShapeAnimation) {
    const { node } = payload;
    // 1. 记录初始状态
    const state = this.getShapeState(node);

    // 2. 解析生成动画
    const timeline = this.getAnimation(payload, () => {
      this.resetShapeState(node, state);
      document.body.removeAttribute("style");
    });

    timeline.play();

    // 在动画播放的过程中，禁止任何操作，不然会导致初始状态异常问题
    document.body.style.pointerEvents = "none";

    /**
     *  3. 记录节点动画信息 - 一个节点可能有多个动画
     *  同一个类型的动画，只能保存一次
     */

    const animationList = node.getAttr("animationList") || [];
    animationList.push({
      nodeID: node.id(),
      name: payload.name,
      duration: payload.duration || 1000,
      delay: payload.delay || 0,
      time: payload.time || "click",
      order: payload.order || animationList.length || 0,
    });
    node.setAttrs({ animationList });
  }
  // 取消动画
  public cancelKonvaAnimation() {}
  // 这个函数用于预览时解析动画
  public applyKonvaAnimation() {}

  // 获取 layer 的动画列表
  public getAnimationList(layer: Konva.Layer): IShapeAnimation[] {
    layer = layer || this.draw.getLayer();
    if (!layer) return [];

    const animationList: IShapeAnimation[] = [];
    layer.children
      .filter((g) => g.getAttr("animationList"))
      .forEach((group) => {
        animationList.push(...group.getAttr("animationList"));
      });

    return animationList;
  }

  // 还原初始状态 - 重新渲染
  private resetShapeState(node: Konva.Node, state: Konva.NodeConfig) {
    const {
      opacity = 1,
      width = 0,
      height = 0,
      scale,
      x = 0,
      y = 0,
      rotation = 0,
    } = state;
    node.opacity(opacity); // 透明度
    node.size({ width, height }); // 尺寸
    node.scale(scale); // 缩放比例
    node.position({ x, y }); // 初始位置
    node.rotation(rotation); // 旋转角度
    this.draw.render();
  }

  // 获取初始状态
  private getShapeState(node: Konva.Node): Konva.NodeConfig {
    // 需要存储的初始状态值 ：opacity、width、height、scale 等
    const opacity = node.opacity();
    const { width, height } = node.size();
    const scale = node.scale();
    const { x, y } = node.position();
    const rotation = node.rotation();
    return {
      opacity,
      width,
      height,
      scale,
      x,
      y,
      rotation,
      // ...
    };
  }

  // 动画集合 - 直接返回的是 tween 动画
  private getAnimation(payload: IShapeAnimation, onComplete: () => void) {
    // 需要 解析参数
    const { node, name } = payload;

    const AnimationMap: IKeyMap<string, () => gsap.core.Timeline> = {
      // 闪烁两次强调
      [ShapeAnimationEnum.flash]: () => ANIMATION_FLASH(node, onComplete),
      // 左右摇晃
      [ShapeAnimationEnum.shakeX]: () => ANIMATION_SHAKEX(node, onComplete),
      // 放大显示
      [ShapeAnimationEnum.heartBeat]: () =>
        ANIMATION_HEARTBEAT(node, onComplete),

      // 顶部落下
      [ShapeAnimationEnum.backInDown]: () =>
        ANIMATION_BACKINDOWN(node, onComplete),
      // 淡入
      [ShapeAnimationEnum.fadeIn]: () => ANIMATION_FADEIN(node, onComplete),
      // 旋转进入
      [ShapeAnimationEnum.rotateIn]: () => ANIMATION_ROTATEIN(node, onComplete),
      // 放大进入
      [ShapeAnimationEnum.zoomIn]: () => ANIMATION_ZOOMIN(node, onComplete),

      // 底部弹出
      [ShapeAnimationEnum.backOutDown]: () =>
        ANIMATION_BACKOUTDOWN(node, onComplete),
      // 淡出
      [ShapeAnimationEnum.fadeOut]: () => ANIMATION_FADEOUT(node, onComplete),
      // 旋转离开
      [ShapeAnimationEnum.rotateOut]: () =>
        ANIMATION_ROTATEOUT(node, onComplete),
      // // 缩小离开
      [ShapeAnimationEnum.zoomOut]: () => ANIMATION_ZOOMOUT(node, onComplete),
    };

    return AnimationMap[name]();
  }
}
